package main

import (
	"fmt"
	"time"
)

var (
	Counter int64

	WAN     = 10000
	Task    = 10 * WAN //100K
	TaskAdd = 100

	TotalNum = Task * TaskAdd
)

func StartAddAtTheSameTime(runIt chan int64, result chan int64) {
	// wait signal to go
	<-runIt

	total := 0
	for i := 0; i < TaskAdd; i++ {
		Counter++
		total++
	}

	// result
	result <- int64(total)
}

func StartAddImmediatelly(runIt chan int64, result chan int64) {

	total := 0
	for {
		select {
		case <-runIt:
			// wait signal to go
			goto quit
		default:
			time.Sleep(time.Nanosecond)

			// Counter++
			a := Counter
			a++
			Counter = a
			total++
			time.Sleep(10 * time.Nanosecond)
		}
	}
quit:
	// result
	result <- int64(total)
}

func main() {

	runItChan := make(chan int64, Task+1)
	resultChan := make(chan int64, Task+1)

	for i := 0; i < Task; i++ {
		if (i % WAN) == 0 {
			fmt.Printf("%dW ", i/WAN)
		}
		// go StartAddAtTheSameTime(runItChan, resultChan)
		go StartAddImmediatelly(runItChan, resultChan)
	}

	fmt.Println("fill channel, in 1s")
	// <-time.After(1 * time.Second)
	<-time.After(60 * time.Second)
	for i := 0; i < Task; i++ {
		runItChan <- int64(i)
	}
	fmt.Println("fill channel done")

	// wait for result
	resultNum := int64(0)
	for i := 0; i < Task; i++ {
		res := <-resultChan
		resultNum = resultNum + res
	}

	fmt.Println("TotalNum should be:", TotalNum)
	fmt.Println("Counter (no lock):", Counter)
	fmt.Println("resultNum:", resultNum)

	// if int64(TotalNum) == Counter {
	if resultNum == Counter {
		fmt.Println("[OK]")
	} else {
		fmt.Println("[NG]")
	}

	fmt.Println("Done..")

	<-time.After(5 * time.Second)

}
